package edu.unc.ils.mrc.vocabulary;


import java.io.File;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jgrapht.UndirectedGraph;
import org.jgrapht.alg.DijkstraShortestPath;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.Multigraph;
import org.openrdf.concepts.skos.core.Concept;
import org.openrdf.elmo.ElmoModule;
import org.openrdf.elmo.sesame.SesameManager;
import org.openrdf.elmo.sesame.SesameManagerFactory;
import org.openrdf.repository.Repository;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.sail.nativerdf.NativeStore;

public class VocabularyGraph extends Vocabulary
{
    String vocabularyName;
    String vocabularyPath;
    
    SesameManager manager;
    NativeStore store;
    Repository repository;
    SesameManagerFactory factory;
    
    int numTerms = 0;
    
    Map<Integer, String> termIdToTermMap = new HashMap<Integer, String>();
    Map<String, Integer> termToTermIdMap = new HashMap<String, Integer>();
    
    UndirectedGraph<Integer, DefaultEdge> graph = 
        new Multigraph<Integer, DefaultEdge>(DefaultEdge.class);
    
    public void open(String path) throws Exception
    {
        this.vocabularyName = new File(path).getName();
        this.vocabularyPath = path;
        

        // Open the Sesame repository
        String indexes = "spoc,ospc";
        this.store = new NativeStore(new File(vocabularyPath), indexes);
        this.repository = new SailRepository(store);
        this.repository.initialize();
        ElmoModule module = new ElmoModule();
        this.factory = new SesameManagerFactory(module, repository);
        this.manager = factory.createElmoManager(); 
        
        init();
    }
    
    public void close() throws Exception
    {
        this.repository.shutDown();
        this.store.shutDown();
    }
    
    public Integer getTermId(String term) {
        return termToTermIdMap.get(term);
    }
    
    public String getTermById(Integer termId) {
        return termIdToTermMap.get(termId);
    }

    public void init() 
    {    
        // Add a root node, since most vocabularies do not have one.
        graph.addVertex(0);
        
        // Assign a term Id to every term and build a word index
        int termId = 1;
        for (Concept concept:  manager.findAll(Concept.class))
        {
            graph.addVertex(termId);  
            String prefLabel = concept.getSkosPrefLabel();
            termIdToTermMap.put(termId, prefLabel);
            termToTermIdMap.put(prefLabel, termId);
            termId++;
        }
                

        // Build the relationship matrix
        for (Concept concept:  manager.findAll(Concept.class)) 
        {
            int tId = termToTermIdMap.get(concept.getSkosPrefLabel());
            
            Set<Concept> broaders = concept.getSkosBroaders();
            if (broaders == null || broaders.size() == 0) 
            {
                DefaultEdge edge = graph.addEdge(0, tId);
            }
            else
            {
                Iterator<Concept> bit = broaders.iterator();
                while (bit.hasNext())
                {
                    try
                    {
                        Concept broader = bit.next();
                        int btId = termToTermIdMap.get(broader.getSkosPrefLabel());
                        DefaultEdge edge = graph.addEdge(tId, btId);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            

            Set<Concept> narrowers = concept.getSkosNarrowers();
            Iterator<Concept> nit = narrowers.iterator();
            while (nit.hasNext())
            {
                try
                {
                    Concept narrower = nit.next();
                    int ntId = termToTermIdMap.get(narrower.getSkosPrefLabel());
                    DefaultEdge edge = graph.addEdge(tId, ntId);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }            
            
           
            Set<Concept> relateds = concept.getSkosRelated();
            Iterator<Concept> rit = relateds.iterator();
            while (rit.hasNext())
            {
                try
                {
                    Concept related = rit.next();
                    int rtId = termToTermIdMap.get(related.getSkosPrefLabel());
                    if (!graph.containsEdge(tId, rtId))
                    {
                        DefaultEdge edge = graph.addEdge(tId, rtId);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }     
           
        }
    }



    @Override
    public String getPrefLabel(int conceptId) throws Exception {
        return termIdToTermMap.get(conceptId);
    }


    @Override
    public boolean isRelated(String term1, String term2) throws Exception {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isBroaderNarrower(String term1, String term2)
            throws Exception {
        
        Integer tId1 = termToTermIdMap.get(term1);
        Integer tId2 = termToTermIdMap.get(term2);
        if (tId1 == null)
        {
            //System.out.println("Failed to lookup term " + term1);
            return false;
        }
        if (tId2 == null)
        {
            //System.out.println("Failed to lookup term " + term1);
            return false;
        }    
        
        DijkstraShortestPath<Integer, DefaultEdge> sp =
            new DijkstraShortestPath<Integer, DefaultEdge>(graph, tId1, tId2);
        
        double d = sp.getPathLength();
        if (d == Double.POSITIVE_INFINITY || d == 0)
            return false;
        else
            return true;
    }

    @Override
    public int getConceptId(String prefLabel) throws Exception {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public int getNextRandom(int conceptId) throws Exception {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public int getNextRandom(int conceptId, int btWeight, int ntWeight,
            int rtWeight) throws Exception {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public List<Term> lookup(String str) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public List<Term> lookupNonStemmed(String str) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public List<Term> lookupWord(String str) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public List<Term> lookupWordStemmed(String str) throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int getSize() {
        // TODO Auto-generated method stub
        return 0;
    }
}
